package com.config;

import com.authentication.manager.InMemoryAuthenticationManager;
import com.nimbusds.jose.proc.SecurityContext;
import com.nimbusds.jwt.proc.DefaultJWTProcessor;
import com.nimbusds.jwt.proc.JWTProcessor;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtDecoders;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider;
import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.access.intercept.AuthorizationFilter;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.DelegatingFilterProxy;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

import static com.common.Oauth2Constant.authorizationEndpointUri;


@Configuration
public class AuthorizationServerConfig {


    @Bean
    public DelegatingFilterProxy delegatingFilterProxy() {
        DelegatingFilterProxy delegatingFilterProxy = new DelegatingFilterProxy();
        delegatingFilterProxy.setTargetBeanName("filterChainProxy");
        return delegatingFilterProxy;
    }

    @Bean
    public FilterRegistrationBean<DelegatingFilterProxy> delegatingFilterProxyRegistrationBean() {
        FilterRegistrationBean<DelegatingFilterProxy> result = new FilterRegistrationBean<>(delegatingFilterProxy());

        result.addUrlPatterns("/**");

        return result;
    }

    @Bean
    public FilterChainProxy filterChainProxy() {
        return new FilterChainProxy(
                Arrays.asList(
                        resourceServerChain()
                )
        );
    }


    @Bean
    public SecurityFilterChain resourceServerChain() {

        BearerTokenAuthenticationFilter bearerTokenAuthenticationFilter = new BearerTokenAuthenticationFilter(
                new ProviderManager(
                        authenticationProvider()
                )
        );

        return new DefaultSecurityFilterChain(
                new AntPathRequestMatcher("/**"),
                Arrays.asList(
                        new CharacterEncodingFilter(StandardCharsets.UTF_8.name()),
                        new ExceptionTranslationFilter(new HttpStatusEntryPoint(HttpStatus.FORBIDDEN)),
                        bearerTokenAuthenticationFilter
                )
        );
    }

    @Bean
    public AuthenticationManager authenticationManager() {
        return new InMemoryAuthenticationManager();
    }


    @Bean
    public AuthenticationProvider authenticationProvider() {

        /*DefaultJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();


        JwtDecoder nimbusJwtDecoder = new NimbusJwtDecoder(jwtProcessor);*/

//        JwtDecoder jwtDecoder = JwtDecoders.fromIssuerLocation("http://localhost:10000/introspection/jwkSet");

        NimbusJwtDecoder decoder = NimbusJwtDecoder.withJwkSetUri("http://localhost:10000/introspection/jwkSet")
                //.jwtProcessorCustomizer(JwtDecoderProviderConfigurationUtils::addJWSAlgorithms)
                .build();

        return new JwtAuthenticationProvider(decoder);

       /* SpringOpaqueTokenIntrospector introspector = new SpringOpaqueTokenIntrospector(
                "http://localhost:10000/introspection/access/token",
                "user_resource_server",
                "user_resource_server_password"
        );

        return new OpaqueTokenAuthenticationProvider(introspector);*/
    }


}
